package com.hundsun.fmbp.deploy.utils;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.springframework.util.StringUtils;

/**
 * @author dangling13236 从Hera项目的Encr类整理而来
 */
public class EncrUtil {
    private static final int RADIX = 16;
    private static final String SEED = "0933910847463829827159347601486730416058";
    public static final String UNIX_OPEN = "${";
    public static final String UNIX_CLOSE = "}";
    public static final String WINDOWS_OPEN = "%%";
    public static final String WINDOWS_CLOSE = "%%";

    public static final String[] SYSTEM_PROPERTIES = new String[] { "java.version", "java.vendor", "java.vendor.url",
            "java.home", "java.vm.specification.version", "java.vm.specification.vendor", "java.vm.specification.name",
            "java.vm.version", "java.vm.vendor", "java.vm.name", "java.specification.version",
            "java.specification.vendor", "java.specification.name", "java.class.version", "java.class.path",
            "java.library.path", "java.io.tmpdir", "java.compiler", "java.ext.dirs",

            "os.name", "os.arch", "os.version",

            "file.separator", "path.separator", "line.separator",

            "user.name", "user.home", "user.dir", "user.country", "user.language", "user.timezone",

            "org.apache.commons.logging.Log", "org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient",
            "org.apache.commons.logging.simplelog.showdatetime", "org.eclipse.swt.browser.XULRunnerInitialized",
            "org.eclipse.swt.browser.XULRunnerPath",

            "sun.arch.data.model", "sun.boot.class.path", "sun.boot.library.path", "sun.cpu.endian", "sun.cpu.isalist",
            "sun.io.unicode.encoding", "sun.java.launcher", "sun.jnu.encoding", "sun.management.compiler",
            "sun.os.patch.level", };

    public EncrUtil() {
    }

    public boolean init() {
        return true;
    }

    public String buildSignature(String mac, String username, String company, String products) {
        try {
            BigInteger bi_mac = new BigInteger(mac.getBytes());
            BigInteger bi_username = new BigInteger(username.getBytes());
            BigInteger bi_company = new BigInteger(company.getBytes());
            BigInteger bi_products = new BigInteger(products.getBytes());

            BigInteger bi_r0 = new BigInteger(SEED);
            BigInteger bi_r1 = bi_r0.xor(bi_mac);
            BigInteger bi_r2 = bi_r1.xor(bi_username);
            BigInteger bi_r3 = bi_r2.xor(bi_company);
            BigInteger bi_r4 = bi_r3.xor(bi_products);

            return bi_r4.toString(RADIX);
        } catch (Exception e) {
            return null;
        }
    }

    public static final boolean checkSignatureShort(String signature, String verify) {
        return getSignatureShort(signature).equalsIgnoreCase(verify);
    }

    public static final String getSignatureShort(String signature) {
        String retval = "";
        if (signature == null) {
            return retval;
        }
        int len = signature.length();
        if (len < 6) {
            return retval;
        }
        retval = signature.substring(len - 5, len);

        return retval;
    }

    public static final String encryptPassword(String password) {
        if (password == null) {
            return "";
        }
        if (password.length() == 0) {
            return "";
        }

        BigInteger bi_passwd = new BigInteger(password.getBytes());

        BigInteger bi_r0 = new BigInteger(SEED);
        BigInteger bi_r1 = bi_r0.xor(bi_passwd);

        return bi_r1.toString(RADIX);
    }

    public static final String decryptPassword(String encrypted) {
        if (encrypted == null) {
            return "";
        }
        if (encrypted.length() == 0) {
            return "";
        }

        BigInteger bi_confuse = new BigInteger(SEED);

        try {
            BigInteger bi_r1 = new BigInteger(encrypted, RADIX);
            BigInteger bi_r0 = bi_r1.xor(bi_confuse);

            return new String(bi_r0.toByteArray());
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * The word that is put before a password to indicate an encrypted form. If
     * this word is not present, the password is considered to be NOT encrypted
     */
    public static final String PASSWORD_ENCRYPTED_PREFIX = "Encrypted ";

    /**
     * Encrypt the password, but only if the password doesn't contain any
     * variables.
     * 
     * @param password
     *            The password to encrypt
     * @return The encrypted password or the
     */
    public static final String encryptPasswordIfNotUsingVariables(String password) {
        String encrPassword = "";
        List<String> varList = new ArrayList<String>();
        getUsedVariables(password, varList, true);
        if (varList.isEmpty()) {
            encrPassword = PASSWORD_ENCRYPTED_PREFIX + EncrUtil.encryptPassword(password);
        } else {
            encrPassword = password;
        }

        return encrPassword;
    }

    public static final String decryptPasswordOptionallyEncrypted(String password) {
        if (!StringUtils.isEmpty(password) && password.startsWith(PASSWORD_ENCRYPTED_PREFIX)) {
            return EncrUtil.decryptPassword(password.substring(PASSWORD_ENCRYPTED_PREFIX.length()));
        }
        return password;
    }

    public static void getUsedVariables(String aString, List<String> list, boolean includeSystemVariables) {
        getUsedVariables(aString, UNIX_OPEN, UNIX_CLOSE, list, includeSystemVariables);
        getUsedVariables(aString, WINDOWS_OPEN, WINDOWS_CLOSE, list, includeSystemVariables);
    }

    /**
     * Search the string and report back on the variables used
     *
     * @param aString
     *            The string to search
     * @param open
     *            the open or "start of variable" characters ${ or %%
     * @param close
     *            the close or "end of variable" characters } or %%
     * @param list
     *            the list of variables to add to
     * @param includeSystemVariables
     *            also check for system variables.
     */
    private static void getUsedVariables(String aString, String open, String close, List<String> list,
            boolean includeSystemVariables) {
        if (aString == null) {
            return;
        }

        int p = 0;
        while (p < aString.length()) {
            // OK, we found something... : start of Unix variable
            if (aString.substring(p).startsWith(open)) {
                // See if it's closed...
                int from = p + open.length();
                int to = aString.indexOf(close, from + 1);

                if (to >= 0) {
                    String variable = aString.substring(from, to);

                    if (indexOfString(variable, list) < 0) {
                        // Either we include the system variables (all)
                        // Or the variable is not a system variable
                        // Or it's a system variable but the value has not been
                        // set (and we offer the user the option to set it)
                        //
                        if (includeSystemVariables || !isSystemVariable(variable)
                                || System.getProperty(variable) == null) {
                            list.add(variable);
                        }
                    }
                    // OK, continue
                    p = to + close.length();
                }
            }
            p++;
        }
    }

    public static boolean isSystemVariable(String aString) {
        return indexOfString(aString, SYSTEM_PROPERTIES) >= 0;
    }

    /**
     * Search for a string in a list of strings and return the index.
     *
     * @param lookup
     *            The string to search for
     * @param list
     *            The ArrayList of strings to look in
     * @return The index of a search string in an array of strings. -1 if not
     *         found.
     */
    public static final int indexOfString(String lookup, List<String> list) {
        if (list == null) {
            return -1;
        }

        for (int i = 0; i < list.size(); i++) {
            String compare = list.get(i);
            if (lookup.equalsIgnoreCase(compare)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Search for a string in an array of strings and return the index.
     *
     * @param lookup
     *            The string to search for
     * @param array
     *            The array of strings to look in
     * @return The index of a search string in an array of strings. -1 if not
     *         found.
     */
    public static final int indexOfString(String lookup, String array[]) {
        if (array == null) {
            return -1;
        }
        if (lookup == null) {
            return -1;
        }

        for (int i = 0; i < array.length; i++) {
            if (lookup.equalsIgnoreCase(array[i])) {
                return i;
            }
        }
        return -1;
    }

}
